#include "os.h"

	// 当你需要在.S文件里实现一个函数的时候，你需要把函数名设置在global里；
	// 如果你只是想调用一个现成的实现好的函数，那么你放在extern里即可

	// 声明本地以下符号是全局的，在其它源文件中可以访问
	.global _start,time_interrupt, syscall_output

	// 当需要引用外部的符号是，使用extern声明。相当于C语言中的extern
	.extern gdtTable, pgDir, os_init, idtTable, task0, task_sched, do_system_call

	// 指定以下的代码生成16位的机器指令，这样才能在启动时的实模式下运行
  	.code16

	// 以下是代码区
 	.text
_start: 
	//初始化段寄存器
	jmp $0,$offset //cs
offset:
	mov $0,%ax
	mov %ax,%ds
	mov %ax,%ss
	mov %ax,%es
	mov %ax,%fs
	mov %ax,%gs
	//设置栈空间
	mov $_start, %esp

//BIOS程序读取指定数据到指定位置
read_self_all:
	mov $0x7E00,%bx //设置读取内容的开头位置
	mov $0x2,  %cx 	//ch:磁道号,cl:起始扇出号；表示从第二个扇区开始
	mov $0x240,%ax  //读取磁盘命令
	mov $0x80, %dx	//选择磁盘号
	int $0x13
	jc read_self_all

	//加载GDT表数据--保护模式
	cli
	lgdt gdt_set //设置GDTR
	lidt idt_set //设置IDTR
	mov $1, %eax
	lmsw %ax //设置CR0，CPU进入保护模式
	jmp $KERNEL_CODE_SEG, $_start_32

    .org 0x1fe
    .byte 0x55,0xaa

	.code32
	.text

_start_32:
	//设置各段寄存器选择子
	mov $KERNEL_DATA_SEG, %ax
	mov %ax,%ds
	mov %ax,%ss
	mov %ax,%es
	mov %ax,%fs
	mov %ax,%gs
	mov $_start, %esp //设置栈空间

	call os_init

//开启分页机制
	//设置分页表地址
	mov $pgDir, %eax
	mov %eax, %cr3

	//设置CR4标志位，允许分页机制为4MB的映射
	mov %cr4, %eax
	orl $(1 << 4), %eax
	mov %eax, %cr4

	//设置CR0标志位，允许开启分页机制
	mov %cr0, %eax
	orl $(1 << 31), %eax
	mov %eax, %cr0  
	
	sti
	; mov $TASK0_TSS_SEG, %ax
	; ltr %ax //设置tr寄存器，指定运行任务与其tss选择子

	; push $APP_DATA_SEG
	; push $task0Dpl3Stack + 1024 * 4;//从高往低压
	; push $0x202		//打开中断
	; push $APP_CODE_SEG
	; push $task0_entry
	; iret



time_interrupt:
	push %ds //将段寄存器ds入栈
	pusha //将通用寄存器的值压栈；（AX, CX, DX, BX, SP, BP, SI, 和 DI 寄存器的值依次入栈）
	mov $0x20, %al
	outb %al, $0x20 //中断处理完成

	mov $KERNEL_DATA_SEG, %ax
	mov %ax, %ds
	call task_sched //通过中断实现任务的切换

	popa
	pop %ds
	iret

syscall_output:
	pusha
	push %ds
	//设置ds寄存器内容
	mov $KERNEL_DATA_SEG,%ax
	mov %ax,%ds

	//从右到左依次压入函数do_system_call参数
	mov %esp, %eax

	push 13*4(%eax)
	push 12*4(%eax)
	push 11*4(%eax)
	call do_system_call

	add $(3*4), %esp //压入的参数供函数使用，使用完后手动弹出

//弹出顺序:ds->通用寄存器->(EIP->CS[远跳转时入栈的])->压入的函数参数(funcNum->str->color[为什么是3个？因为在系统调用描述符设置时设置好了])->(ESP->SS[硬件自动拷贝入栈])

	pop %ds
	popa
	retf $(3 * 4) //弹出我们手动压入的三个参数


; task0_entry:
; 	mov %ss, %ax
; 	mov %ax,%ds
; 	mov %ax,%es
; 	mov %ax,%fs
; 	mov %ax,%gs
; 	jmp task0

gdt_set: 
	.word 256 * 8 - 1
	.long gdtTable

idt_set:
	.word 256 * 8 - 1
	.long idtTable